#include "app_message.h"

// 将二进制数据转换为字符串, 调用者需要负责释放str
static char *bin_to_str(unsigned char *binary, int len)
{
    char *hex_str = malloc(len * 2 + 1);
    if (!hex_str)
    {
        log_warn("Not enough memory");
        return NULL;
    }

    for (int i = 0; i < len; i++)
    {
        sprintf(hex_str + i * 2, "%02X", binary[i]);
    }
    hex_str[len * 2] = '\0';
    return hex_str;
}

// 将字符串转化为二进制数据，返回实际转化的长度
static int str_to_bin(char *hex_str, unsigned char *binary, int len)
{
    if (strlen(hex_str) % 2 != 0)
    {
        log_warn("Hex string is not valid");
        return -1;
    }
    if (len < (int)(strlen(hex_str) / 2))
    {
        log_warn("Buffer len is not enough");
        return -1;
    }
    len = strlen(hex_str) / 2;
    for (int i = 0; i < len; i++)
    {
        // 现在需要转化的字节有两个，分别是hex_str[i*2]和hex_str[i*2+1]
        char high = hex_str[i * 2];
        char low = hex_str[i * 2 + 1];

        // 首先处理高位
        if (high <= '9' && high >= '0')
        {
            binary[i] = high - '0';
        }
        else if (high >= 'a' && high <= 'f')
        {
            binary[i] = high - 'a' + 10;
        }
        else if (high >= 'A' && high <= 'F')
        {
            binary[i] = high - 'A' + 10;
        }
        binary[i] <<= 4;

        // 再处理低位
        if (low <= '9' && low >= '0')
        {
            binary[i] |= low - '0';
        }
        else if (low >= 'a' && low <= 'f')
        {
            binary[i] |= low - 'a' + 10;
        }
        else if (low >= 'A' && low <= 'F')
        {
            binary[i] |= low - 'A' + 10;
        }
    }
    return len;
}

/**
 * @brief 将从外设数据封装为消息帧
 *
 * @param message  消息指针
 * @param data     接收到的外设数据
 * @param len      外设数据的数据总长度
 * @return int 0 成功，-1 失败
 */
int app_message_DataToMessage(Message *message, void *data, int len)
{
    // 1.初始化message
    memset(message, 0, sizeof(Message));

    // 2.读取类型和长度
    memcpy(&message->connection_type, data, 1);
    memcpy(&message->id_len, data + 1, 1);
    memcpy(&message->data_len, data + 2, 1);

    // 3.
    if (len != message->id_len + message->data_len + 3)
    {
        log_warn("Message is not valid");
        return -1;
    }

    message->payload = malloc(message->id_len + message->data_len);

    if (!message->payload)
    {
        log_warn("Not enough for message");
        return -1;
    }

    memcpy(message->payload, data + 3, message->id_len + message->data_len);
    return 0;
}

/**
 * @brief  将接收到的json字符串封装成消息帧
 * 
 * @param message  消息指针
 * @param json_str json字符串
 * @param len      json字符串长度
 * @return int     0 成功，-1 失败
 */
int app_message_JsonToMessage(Message *message, char *json_str, int len)
{
    // 1.使用cJSON解析字符串
    // cJSON_ParseWithLength()用于解析 JSON 字符串，并返回一个 cJSON 结构体指针
    cJSON *json_object = cJSON_ParseWithLength(json_str, len);

    // 2. 读取ConnectionType
    // cJSON_GetObjectItem()用于从一个 cJSON 结构体中获取指定键的值。
    cJSON *conn_type_cJson = cJSON_GetObjectItem(json_object, "connection_type");
    message->connection_type = conn_type_cJson->valueint;

    // 3.读取id和data的长度
    cJSON *id_cJson = cJSON_GetObjectItem(json_object, "id");
    if (strlen(id_cJson->valuestring) % 2 != 0)
    {
        log_warn("Message is not valid");
        return -1;
    }
    message->id_len = strlen(id_cJson->valuestring) / 2;

    cJSON *data_cJson = cJSON_GetObjectItem(json_object, "data");
    if (strlen(data_cJson->valuestring) % 2 != 0)
    {
        log_warn("Message is not valid");
        return -1;
    }
    message->data_len = strlen(data_cJson->valuestring) / 2;



    // 4.申请message的payload内存
    message->payload = malloc(message->id_len + message->data_len);

    if (!message->payload)
    {
        //内存申请失败
        log_warn("Not enough memory for message");
        return -1;
    }

    if (str_to_bin(id_cJson->valuestring, message->payload, message->id_len) < 0)
    {
        //id字符串转化为设备的id数据失败
        log_warn("Convertion failed");
        free(message->payload);
        return -1;
    }
    if (str_to_bin(data_cJson->valuestring, message->payload + message->id_len, message->data_len) < 0)
    {
        //data字符串转化为设备的负载数据失败
        log_warn("Convertion failed");
        free(message->payload);
        return -1;
    }

    //释放cJSON结构体变量的内存
    cJSON_Delete(json_object);
    return 0;
}

/**
 * @brief  拆封消息帧转化为外设数据
 * 
 * @param message    消息指针
 * @param data       发送给外设的数据
 * @param len        数据长度
 * @return int       成功返回实际保存长度，-1 失败
 */
int app_message_MessageToData(Message *message, void *data, int len)
{
    // 将来保存外设数据需要的长度为 3个字节元数据和 id_len + data_len长度的数据
    int total_len = message->id_len + message->data_len + 3;
    if (len < total_len)
    {
        log_warn("Buffer not enough for message");
        return -1;
    }

    memcpy(data, &message->connection_type, 1);
    memcpy(data + 1, &message->id_len, 1);
    memcpy(data + 2, &message->data_len, 1);
    memcpy(data + 3, message->payload, message->id_len + message->data_len);

    return total_len;
    return 0;
}

/**
 * @brief 拆封消息帧转化为json字符串
 * 
 * @param message    消息指针
 * @param json_str   json字符串
 * @param len        json字符串长度
 * @return int        0 成功，-1 失败
 */
int app_message_MessageToJson(Message *message, char *json_str, int len)
{
    // 首先生成Json Object
    cJSON *json_object = cJSON_CreateObject();

    cJSON_AddNumberToObject(json_object, "connection_type", message->connection_type);

    cJSON_AddStringToObject(json_object, "id", bin_to_str(message->payload, message->id_len));
    cJSON_AddStringToObject(json_object, "data", bin_to_str(message->payload + message->id_len, message->data_len));
    
    char *str = cJSON_PrintUnformatted(json_object);    //将cJSON结构体转化为无格式化的json字符串
    
    if (len < (int)(strlen(str) + 1))
    {
        log_warn("json_str's length not enough for message");
        return -1;
    }
    strcpy(json_str, str);

    cJSON_free(str);
    cJSON_Delete(json_object);
    return 0;
}

/**
 * @brief 释放message所占的内存
 * 
 * @param message    消息指针
 */
void app_message_free(Message *message)
{
    if (message->payload)
    {
        free(message->payload);
        message->payload = NULL;
    }
}
